package com.crm.service.impl;

import com.crm.common.utils.DateUtils;
import com.crm.common.utils.SecurityUtils;
import com.crm.domain.Activity;
import com.crm.domain.Business;
import com.crm.domain.Clue;
import com.crm.domain.Contract;
import com.crm.domain.vo.CourseVo;
import com.crm.mapper.ActivityMapper;
import com.crm.mapper.IBusinessMapper;
import com.crm.mapper.ContractMapper;
import com.crm.mapper.CourseMapper;
import com.crm.service.ContractService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.math.BigDecimal;
import java.util.List;

@Service
public class ContractServiceImpl implements ContractService{
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private IBusinessMapper businessMapper;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private ActivityMapper activityMapper;


    /**
     * 根据合同 ID 查询单个合同信息
     *
     * 该方法会调用 TbContractMapper 中的对应方法，根据传入的合同 ID 从数据库中查询合同信息。

    /**
     * 插入一个新的合同记录
     *
     * 此方法会为传入的合同对象设置一系列必要的属性，如业务主键、创建人、创建时间、部门 ID 和状态，
     /**
     * 根据合同的 ID 查询单个合同信息
     *
     * 该方法会调用 TbContractMapper 中的对应方法，根据传入的合同 ID 从数据库中查询合同信息。
     * 如果数据库中存在该 ID 对应的合同记录，则返回该合同对象；若不存在，则返回 null。
     *
     * @param id 要查询的合同的唯一标识，为 Long 类型
     * @return 返回查询到的合同对象，若未找到则返回 null，类型为 TbContract
     */
    @Override
    public Contract selectContractById(Long id) {
        // 调用 mapper 方法，根据合同 ID 查询合同信息
        return contractMapper.selectContractById(id);
    }

    /**
     * 根据查询条件查询合同列表
     * 若当前用户不是管理员，会将查询条件中的创建人设置为当前用户的用户名
     *
     * @param queryConditon 包含查询条件的合同对象，用于筛选符合条件的合同
     * @return 返回符合查询条件的合同列表，如果没有符合条件的记录则返回空列表
     */
    @Override
    public List<Contract> selectContract(Contract queryConditon) {
        // 检查当前用户是否为管理员
        if (!SecurityUtils.getAdmin().equals(SecurityUtils.getUserId())) {
            // 当前用户不是admin，设置查询条件中的创建人为当前用户的用户名
            queryConditon.setCreateBy(SecurityUtils.getUsername());
        }
        // 调用 mapper 方法，根据查询条件查询合同列表
        List<Contract> list = contractMapper.selectContractList(queryConditon);
        // 返回查询到的合同列表
        return list;
    }

    /**
     * 插入一个新的合同记录
     *
     * 此方法会为传入的合同对象设置一系列必要的属性，如业务主键、创建人、创建时间、部门 ID 和状态，
     * 并调用 setOrder 方法进行额外的订单相关设置，最后将该合同对象插入到数据库中。
     *
     * @param contract 要插入的合同对象，包含合同的基本信息
     * @return 插入操作影响的行数，若插入成功则返回 1，失败则返回 0
     */
    @Override
    public int insertContract(Contract contract) {
        // 生成一个唯一的业务主键，使用系统的纳秒时间
        String businessKey = "" + System.nanoTime();
        // 设置合同的 ID 为生成的业务主键
        contract.setId(businessKey);
        // 设置合同的创建人，值为当前登录用户的用户名
        contract.setCreateBy(SecurityUtils.getUsername());
        // 设置合同的创建时间为当前时间
        contract.setCreateTime(DateUtils.getNowDate());
        // 重复设置创建人，可考虑移除重复代码
        contract.setCreateBy(SecurityUtils.getUsername());
        // 重复设置创建时间，可考虑移除重复代码
        contract.setCreateTime(DateUtils.getNowDate());
        // 设置合同所属的部门 ID，值为当前登录用户的部门 ID
        contract.setDeptId(SecurityUtils.getDeptId());
        // 设置合同的状态为“全部完成”
        contract.setStatus("4"); // 状态(待审核1，已通过2，已驳回3 全部完成4)
        // 调用 setOrder 方法进行订单相关的设置
        setOrder(contract);
        // 调用 mapper 方法将合同对象插入到数据库中，并返回插入操作影响的行数
        return contractMapper.insertContract(contract);
    }

    /**
     * 根据商机 ID 将商机转换为合同
     *
     * 该方法会检查商机中是否选择了课程，如果未选择课程，则抛出运行时异常。
     * 若商机已选择课程，会将商机状态更新为已转换为客户，然后将商机的部分信息复制到合同对象中，
     * 并设置合同的创建时间和关联的商机 ID，最后插入新的合同记录。
     *
     * @param businessId 商机的唯一标识，用于查询对应的商机信息
     * @param contract 要插入的合同对象，将根据商机信息进行更新
     * @return 返回插入合同操作影响的行数，如果插入成功则返回 1，失败则返回 0
     * @throws RuntimeException 如果商机中未选择课程，将抛出此异常
     */
    @Override
    public int changeContract(Long businessId, Contract contract) {
        // 根据商机 ID 查询对应的商机信息
        Business business = businessMapper.selectBusinessById(businessId);
        // 检查商机中是否选择了课程
        if (business.getCourseId() == null) {
            // 若未选择课程，抛出运行时异常
            throw new RuntimeException("商机里面没有选择课程,不能转换课程");
        }
        // 将商机的状态设置为已转换为客户
        business.setStatus(Clue.StatusType.TOCUSTOMER.getValue());
        // 更新商机信息到数据库
        businessMapper.updateBusiness(business);
        // 设置合同的创建时间为当前时间
        contract.setCreateTime(DateUtils.getNowDate());
        // 设置合同关联的商机 ID
        contract.setBusinessId(businessId);
        // 将商机的部分信息复制到合同对象中
        BeanUtils.copyProperties(business, contract);
        // 插入新的合同记录并返回插入操作影响的行数
        return insertContract(contract);
    }

    /**
     * 更新合同信息
     *
     * 该方法会将传入的合同对象的状态设置为 "2"，并调用 setOrder 方法进行订单相关设置，
     * 最后调用 TbContractMapper 的 updateTbContract 方法将更新后的合同信息保存到数据库中。
     *
     * @param contract 包含要更新信息的合同对象
     * @return 返回更新操作影响的行数，若更新成功则返回 1，失败则返回 0
     */
//    @Override
//    public int updateContract(Contract contract) {
//        // 设置合同的状态为 "2"
//        contract.setStatus("2");
//        // 调用 setOrder 方法进行订单相关设置
//        setOrder(contract);
//        // 调用 mapper 方法将更新后的合同信息保存到数据库中，并返回更新操作影响的行数
//        return contractMapper.updateContract(contract);
//    }

    /**
     * 根据课程和活动信息设置合同的订单价格和折扣类型
     *
     * 该方法根据传入的合同对象中的课程 ID 和活动 ID，从数据库中查询对应的课程和活动信息。
     * 根据活动的类型和具体规则，计算合同的订单价格并设置折扣类型。
     * 如果活动存在，根据活动类型（课程折扣或代金券）进行不同的价格计算；
     * 如果活动不存在，则设置为无折扣，订单价格为课程原价。
     *
     * @param contract 包含课程 ID 和活动 ID 的合同对象，用于计算订单价格和设置折扣类型
     */
    private void setOrder(Contract contract) {
        // 根据合同中的课程 ID 查询课程信息
        CourseVo course = courseMapper.getCourseById(contract.getCourseId());
        // 设置合同的课程价格为查询到的课程价格
        contract.setCoursePrice(course.getPrice());
        // 根据合同中的活动 ID 查询活动信息
        Activity Activity = activityMapper.getActivityById(contract.getActivityId());
        // 如果活动信息不为空
        if (Activity != null) {
            // 检查活动类型是否为 "1"（表示课程折扣）
            if ("1".equals(Activity.getType())) {
                // 设置折扣类型为 "课程折扣"
                contract.setDiscountType("课程折扣");
                // 将课程价格转换为 BigDecimal 类型
                BigDecimal price = new BigDecimal(course.getPrice());
                // 将活动折扣转换为 BigDecimal 类型
                BigDecimal discount = new BigDecimal(Activity.getDiscount());
                // 计算折扣后的订单价格，折扣除以 10 并保留两位小数，向上取整
                BigDecimal order = price.multiply(discount.divide(new BigDecimal(10), 2, BigDecimal.ROUND_CEILING));
                // 将计算得到的订单价格设置到合同对象中
                contract.setOrder(order.floatValue());
            } else {
                // 检查代金券金额是否大于等于课程原价的 50%
                if (Activity.getVouchers() >= course.getPrice() / 2) {
                    // 若满足条件，订单价格设置为课程原价
                    contract.setOrder(course.getPrice());
                    // 设置折扣类型为提示信息，表明代金券不能使用
                    contract.setDiscountType("代金券大于原课程50%,不能使用代金券");
                } else {
                    // 若不满足条件，设置折扣类型为 "代金券"
                    contract.setDiscountType("代金券");
                    // 订单价格为课程原价减去代金券金额
                    contract.setOrder(course.getPrice() - Activity.getVouchers());
                }
            }
        } else {
            // 若活动信息为空，设置折扣类型为 "无折扣"
            contract.setDiscountType("无折扣");
            // 订单价格设置为课程原价
            contract.setOrder(course.getPrice());
        }
    }
}

